/*
 *    Copyright (c) 2018-2025, cloud All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: cloud
 */
package com.fuyao.cloud.space.edifice.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fuyao.cloud.common.core.constant.CommonConstants;
import com.fuyao.cloud.common.data.resolver.NumberResolver;
import com.fuyao.cloud.common.excel.vo.ErrorMessage;
import com.fuyao.cloud.space.constant.RegionalConstant;
import com.fuyao.cloud.space.entity.RoomHouse;
import com.fuyao.cloud.space.entity.RoomStorey;
import com.fuyao.cloud.space.house.mapper.RoomHouseMapper;
import com.fuyao.cloud.space.storey.mapper.RoomStoreyMapper;
import com.fuyao.cloud.space.storey.service.RoomStoreyService;
import com.fuyao.cloud.space.vo.ExcelExportEdificeVO;
import com.fuyao.cloud.space.vo.ExcelImportEdificeVO;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyao.cloud.common.core.util.DictItemOption;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.data.datascope.DataScope;
import com.fuyao.cloud.common.data.resolver.DictItemResolver;
import com.fuyao.cloud.space.constant.EdificeConstant;
import com.fuyao.cloud.space.edifice.mapper.RoomEdificeMapper;
import com.fuyao.cloud.space.edifice.service.RoomEdificeService;
import com.fuyao.cloud.space.entity.RoomEdifice;
import com.fuyao.cloud.space.entity.RoomRegional;
import com.fuyao.cloud.space.regional.mapper.RoomRegionalMapper;
import com.fuyao.cloud.space.vo.RoomEdificeCreateVO;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 楼栋管理
 *
 * @author liyue
 * @date 2021-11-12 16:03:22
 */
@Service
@AllArgsConstructor
public class RoomEdificeServiceImpl extends ServiceImpl<RoomEdificeMapper, RoomEdifice> implements RoomEdificeService {

    private final RoomRegionalMapper regionalMapper;
    private final RoomStoreyMapper roomStoreyMapper;
    private final RoomHouseMapper houseMapper;

    @Override
    public boolean save(RoomEdifice entity) {
        setFieldValue(entity);
        return super.save(entity);
    }

    @Override
    public boolean updateById(RoomEdifice entity) {
        setFieldValue(entity);
        return super.updateById(entity);
    }

    @Override
    public R create() {
        RoomEdificeCreateVO createVO = new RoomEdificeCreateVO();
        createVO.setUnid(UUID.randomUUID().toString());
        List<String> types = ListUtil.of(EdificeConstant.OEDIFICE_OPTION_TYPES);
        R result = DictItemResolver.getDictItemTypeList(types);
        Map<String, List<DictItemOption>> resultMap = (Map<String, List<DictItemOption>>) result.getData();
        // 字典信息
        RoomEdificeCreateVO.DictOption dictOption = new RoomEdificeCreateVO.DictOption();
        dictOption.setBuildingStructureList(resultMap.get(EdificeConstant.EDIFICE_BUILDING_STRUCTURE));
        dictOption.setEarthquakeResistanceLevelList(resultMap.get(EdificeConstant.EDIFICE_EARTHQUAKE_RESISTANCE_LEVEL));
        dictOption.setEdificeScurceAssetsList(resultMap.get(EdificeConstant.EDIFICE_SCURCE_ASSETS));
        dictOption.setUsageStatusList(resultMap.get(EdificeConstant.EDIFICE_USAGE_STATUS));
        createVO.setDictOption(dictOption);
        return R.ok(createVO);
    }

    @Override
    public List<ExcelExportEdificeVO> listEdifice(QueryWrapper<RoomEdifice> query) {
        // 查询字典信息
        Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(EdificeConstant.OEDIFICE_OPTION_TYPES);

        List<RoomEdifice> fyRoomEdifices = this.baseMapper.selectListByScope(query, new DataScope());
        return fyRoomEdifices.stream().map(entity -> {
            ExcelExportEdificeVO exportVO = new ExcelExportEdificeVO();
            BeanUtils.copyProperties(entity, exportVO);
            exportVO.setBuildingStructure(DictItemResolver.getDictOptionLabel(resultMap.get(EdificeConstant.EDIFICE_BUILDING_STRUCTURE), entity.getBuildingStructure()));
            exportVO.setStatus(DictItemResolver.getDictOptionLabel(resultMap.get(EdificeConstant.EDIFICE_USAGE_STATUS), entity.getStatus()));
            exportVO.setSeismicGrade(DictItemResolver.getDictOptionLabel(resultMap.get(EdificeConstant.EDIFICE_EARTHQUAKE_RESISTANCE_LEVEL), entity.getSeismicGrade()));
            exportVO.setSourceAssets(DictItemResolver.getDictOptionLabel(resultMap.get(EdificeConstant.EDIFICE_SCURCE_ASSETS), entity.getSourceAssets()));
            return exportVO;
        }).collect(Collectors.toList());
    }

    @Override
    public R importEdifice(List<ExcelImportEdificeVO> excelVOList, BindingResult bindingResult) {
        // 通用校验获取失败的数据
        List<ErrorMessage> errorMessageList = (List<ErrorMessage>) bindingResult.getTarget();
        // 个性化校验逻辑
        List<RoomRegional> regionalList = regionalMapper.selectList(Wrappers.emptyWrapper());
        Map<String, List<DictItemOption>> resultMap = DictItemResolver.getDictOptionResultMap(EdificeConstant.OEDIFICE_OPTION_TYPES);

        if (CollUtil.isEmpty(excelVOList)) {
            assert errorMessageList != null;
            errorMessageList.add(new ErrorMessage("无数据导入"));
            return R.failed(errorMessageList);
        }
        // 执行数据插入操作 组装 FyRoomRegional
        for (int i = 0; i < excelVOList.size(); i++) {
            ExcelImportEdificeVO excel = excelVOList.get(i);
            Set<String> errorMsg = new HashSet<>();

            if (StrUtil.isNotEmpty(excel.getCode())) {
                LambdaQueryWrapper<RoomEdifice> queryWrapper = Wrappers.<RoomEdifice>lambdaQuery().eq(RoomEdifice::getCode, excel.getCode());
                long count = this.count(queryWrapper);
                if (count > 0) {
                    errorMsg.add(String.format(" 楼栋编码已存在 %s ", excel.getCode()));
                }
            }
            // 拷贝属性
            RoomEdifice edifice = new RoomEdifice();
            BeanUtils.copyProperties(excel, edifice);
            // 验证父区域编码
            if (!StrUtil.isEmpty(excel.getRegionalFullcode())) {
                Optional<RoomRegional> roomRegionalOptional = regionalList.stream().
                        filter(regional -> regional.getCode().equals(excel.getRegionalFullcode())).findFirst();
                if (roomRegionalOptional.isPresent()) {
                    RoomRegional roomRegional = roomRegionalOptional.get();
                    edifice.setRegionalId(roomRegional.getId());
                    edifice.setRegionalMc(roomRegional.getName());
                    edifice.setRegionalFullcode(roomRegional.getFullcode());
                } else {
                    errorMsg.add(String.format("%s:所属区域编码不存在 ", excel.getRegionalFullcode()));
                }
            }
            // 名称转字典编码
            edifice.setBuildingStructure(DictItemResolver.getDictOptionValue(resultMap.get(EdificeConstant.EDIFICE_BUILDING_STRUCTURE), excel.getBuildingStructure()));
            edifice.setStatus(DictItemResolver.getDictOptionValue(resultMap.get(EdificeConstant.EDIFICE_USAGE_STATUS), excel.getStatus()));
            edifice.setSeismicGrade(DictItemResolver.getDictOptionValue(resultMap.get(EdificeConstant.EDIFICE_EARTHQUAKE_RESISTANCE_LEVEL), excel.getSeismicGrade()));
            edifice.setSourceAssets(DictItemResolver.getDictOptionValue(resultMap.get(EdificeConstant.EDIFICE_SCURCE_ASSETS), excel.getSourceAssets()));
            // 数据合法情况
            if (CollUtil.isEmpty(errorMsg)) {
                insertExcelEdifice(excel, edifice);
            } else {
                // 数据不合法情况
                errorMessageList.add(new ErrorMessage((long) (i + 2), errorMsg));
            }
        }
        if (CollUtil.isNotEmpty(errorMessageList)) {
            return R.failed(errorMessageList);
        }
        return R.ok();
    }

    @Override
    public List<Tree<String>> selectTree() {
        // 权限内空间信息
        List<TreeNode<String>> collect = getTreeNode();
        return TreeUtil.build(collect, RegionalConstant.REGIONAL_TREE_NAME + ".0");
    }

    @Override
    public List<TreeNode<String>> getTreeNode() {
        // 查询全部区域
        List<RoomRegional> regionalAllList = regionalMapper.selectList(Wrappers.emptyWrapper());

        // 查询全部楼栋
        List<RoomEdifice> edificeAllList = baseMapper.selectList(Wrappers.emptyWrapper());

        // 查询数据权限内部门
        List<Long> storeyOwnIdList = baseMapper.selectListByScope(Wrappers.emptyWrapper(), new DataScope()).stream()
                .map(RoomEdifice::getDeptId).collect(Collectors.toList());
        // 树
        List<TreeNode<String>> collect = new ArrayList<>();
        List<TreeNode<String>> regionalTreeList = regionalAllList.stream()
                .sorted(Comparator.comparing(RoomRegional::getCreateTime)).map(regional -> {
                    TreeNode<String> treeNode = new TreeNode();
                    treeNode.setId(RegionalConstant.REGIONAL_TREE_NAME + "." + regional.getId());
                    treeNode.setParentId(RegionalConstant.REGIONAL_TREE_NAME + "." + regional.getParentId());
                    treeNode.setName(regional.getName());
                    treeNode.setWeight(regional.getOrdernumber());
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("isLock", !storeyOwnIdList.contains(regional.getDeptId()));
                    extra.put("createTime", regional.getCreateTime());
                    extra.put("affiliName", RegionalConstant.REGIONAL_TREE_NAME);
                    extra.put("affiliParentName", RegionalConstant.REGIONAL_TREE_NAME);
                    extra.put("idCard", regional.getId());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());
        collect.addAll(regionalTreeList);
        // 添加楼栋数据
        List<TreeNode<String>> edigiceTreeList = edificeAllList.stream()
                .sorted(Comparator.comparing(RoomEdifice::getCreateTime)).map(edifice -> {
                    TreeNode<String> treeNode = new TreeNode();
                    treeNode.setId(EdificeConstant.EDIFICE_TREE_NAME + "." + edifice.getId());
                    treeNode.setParentId(RegionalConstant.REGIONAL_TREE_NAME + "." + edifice.getRegionalId());
                    treeNode.setName(edifice.getName());
                    treeNode.setWeight(edifice.getOrdernumber());
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("isLock", !storeyOwnIdList.contains(edifice.getDeptId()));
                    extra.put("createTime", edifice.getCreateTime());
                    extra.put("affiliName", EdificeConstant.EDIFICE_TREE_NAME);
                    extra.put("affiliParentName", RegionalConstant.REGIONAL_TREE_NAME);
                    extra.put("idCard", edifice.getId());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());
        // 添加根节点
        collect.addAll(edigiceTreeList);
        return collect;
    }

    @Override
    public List<Long> getTreeParam(Long id, String affiliName) {
        List<Long> ids = new ArrayList<>();
        if (affiliName.equals(RegionalConstant.REGIONAL_TREE_NAME)) {
            List<Long> regionParentIds = this.regionalMapper.getIdByParentId(id);
            if (regionParentIds != null && regionParentIds.size() > 0) {
                ids = this.baseMapper.getIdByParentIds(regionParentIds);
            } else {
                ids = this.baseMapper.getIdByParentId(id);
            }
        }
        return ids;
    }

    @Override
    public List<Tree<String>> lazyTree(Long regionalId) {
        // lambda 查询条件
        LambdaQueryWrapper<RoomEdifice> wrappers = Wrappers.<RoomEdifice>lambdaQuery().eq(RoomEdifice::getRegionalId, regionalId);
        // 查询全部楼层
        List<RoomEdifice> edificeAllList = baseMapper.selectList(wrappers);
        // 查询数据权限内部门
        List<Long> storeyOwnIdList = baseMapper.selectListByScope(wrappers, new DataScope()).stream()
                .map(RoomEdifice::getDeptId).collect(Collectors.toList());

        if (edificeAllList.size() == 0) {
            return new ArrayList<>();
        }
        // 添加楼栋数据
        List<TreeNode<String>> edigiceTreeList = edificeAllList.stream()
                .sorted(Comparator.comparing(RoomEdifice::getCreateTime)).map(edifice -> {
                    TreeNode<String> treeNode = new TreeNode();
                    treeNode.setId(EdificeConstant.EDIFICE_TREE_NAME + "." + edifice.getId());
                    treeNode.setParentId(RegionalConstant.REGIONAL_TREE_NAME + "." + edifice.getRegionalId());
                    treeNode.setName(edifice.getName());
                    treeNode.setWeight(edifice.getOrdernumber());
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("isLock", !storeyOwnIdList.contains(edifice.getDeptId()));
                    extra.put("createTime", edifice.getCreateTime());
                    extra.put("affiliName", EdificeConstant.EDIFICE_TREE_NAME);
                    extra.put("affiliParentName", RegionalConstant.REGIONAL_TREE_NAME);
                    extra.put("idCard", edifice.getId());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());
        // 权限内空间信息
        return TreeUtil.build(edigiceTreeList, RegionalConstant.REGIONAL_TREE_NAME + "." + regionalId);
    }

    @Override
    public List<Tree<String>> lazyTree(String regionalId) {
        String[] vals = regionalId.split("-");
        if (vals.length == 2) {
            if (!vals[0].equals(RegionalConstant.REGIONAL_TREE_NAME)) {
                return new ArrayList<>();
            }
        }
        return this.lazyTree(Long.valueOf(vals[1]));
    }

    @Override
    public boolean removeById(Serializable id) {
        LambdaQueryWrapper<RoomStorey> queryWrapper = Wrappers.<RoomStorey>lambdaQuery().eq(RoomStorey::getEdificeId, id);
        long count = roomStoreyMapper.selectCount(queryWrapper);
        Assert.isTrue((count <= 0), "该楼栋信息关联楼层信息，请选删除关联楼层信息数据后，再删除楼栋数据");

        LambdaQueryWrapper<RoomHouse> houseLambdaQueryWrapper = Wrappers.<RoomHouse>lambdaQuery().eq(RoomHouse::getEdificeId, id);
        Long houseCount = houseMapper.selectCount(houseLambdaQueryWrapper);
        Assert.isTrue((houseCount <= 0), "该楼栋信息关联房屋信息，请选删除关联房屋信息数据后，再删除楼栋数据");
        return super.removeById(id);
    }

    /**
     * 保存方法
     *
     * @param excel   导入对象
     * @param edifice 楼栋对象
     */
    private void insertExcelEdifice(ExcelImportEdificeVO excel, RoomEdifice edifice) {
        setFieldValue(edifice);
        super.save(edifice);
    }

    private void setFieldValue(RoomEdifice edifice) {
        // 自动生成楼栋编号
        if (StrUtil.isEmpty(edifice.getCode())) {
            String numberStr = NumberResolver.getNumberStr(EdificeConstant.EDIFICE_TYPE, EdificeConstant.EDIFICE_CODE).getData();
            edifice.setCode(numberStr);
        }
        // 自动设置排序号
        if (edifice.getOrdernumber() == null || edifice.getOrdernumber() == 0) {
            Long orderNum = NumberResolver.getNumberValue(EdificeConstant.DEFAULT_TYPE, EdificeConstant.EDIFICE_CODE).getData();
            edifice.setOrdernumber(orderNum.intValue());
        }
        // 如果区域信息为空直接抛出异常
        Assert.isTrue(ObjectUtils.isEmpty(edifice.getRegionalId()) || edifice.getRegionalId() <= 0);
        RoomRegional fyRoomRegional = this.regionalMapper.selectById(edifice.getRegionalId());

        edifice.setRegionalMc(fyRoomRegional.getName());
        edifice.setRegionalFullcode(fyRoomRegional.getFullcode());
        // 数据全编码
        edifice.setDataCode(fyRoomRegional.getDataCode() + "." + edifice.getCode());
    }

    @Override
    public List<Tree<String>> selectEdificeTree() {
        // 查询全部楼层
        List<RoomEdifice> edificeAllList = baseMapper.selectList(Wrappers.emptyWrapper());
        // 查询数据权限内部门
        List<Long> storeyOwnIdList = baseMapper.selectListByScope(Wrappers.emptyWrapper(), new DataScope()).stream()
                .map(RoomEdifice::getDeptId).collect(Collectors.toList());

        if (edificeAllList.size() == 0) {
            return new ArrayList<>();
        }
        // 添加楼栋数据
        List<TreeNode<String>> edigiceTreeList = edificeAllList.stream()
                .sorted(Comparator.comparing(RoomEdifice::getCreateTime)).map(edifice -> {
                    TreeNode<String> treeNode = new TreeNode();
                    treeNode.setId(EdificeConstant.EDIFICE_TREE_NAME + "." + edifice.getId());
                    treeNode.setParentId(RegionalConstant.REGIONAL_TREE_NAME + "." + edifice.getRegionalId());
                    treeNode.setName(edifice.getName());
                    treeNode.setWeight(edifice.getOrdernumber());
                    // 有权限不返回标识
                    Map<String, Object> extra = new HashMap<>(8);
                    extra.put("isLock", !storeyOwnIdList.contains(edifice.getDeptId()));
                    extra.put("createTime", edifice.getCreateTime());
                    extra.put("affiliName", EdificeConstant.EDIFICE_TREE_NAME);
                    extra.put("affiliParentName", RegionalConstant.REGIONAL_TREE_NAME);
                    extra.put("idCard", edifice.getId());
                    treeNode.setExtra(extra);
                    return treeNode;
                }).collect(Collectors.toList());
        // 权限内空间信息
        return TreeUtil.build(edigiceTreeList, "-1");
    }

    @Override
    public R batchDelete(List<Long> ids) {
        LambdaQueryWrapper<RoomStorey> queryWrapper = Wrappers.<RoomStorey>lambdaQuery().in(RoomStorey::getEdificeId, ids);
        long count = roomStoreyMapper.selectCount(queryWrapper);
        Assert.isTrue((count <= 0), "该楼栋信息关联楼层信息，请选删除关联楼层信息数据后，再删除楼栋数据");

        LambdaQueryWrapper<RoomHouse> houseLambdaQueryWrapper = Wrappers.<RoomHouse>lambdaQuery().eq(RoomHouse::getEdificeId, ids);
        Long houseCount = houseMapper.selectCount(houseLambdaQueryWrapper);
        Assert.isTrue((houseCount <= 0), "该楼栋信息关联房屋信息，请选删除关联房屋信息数据后，再删除楼栋数据");

        boolean remove = this.removeByIds(ids);
        if (remove) {
            return R.ok(CommonConstants.SUCCESS, String.format("成功删除%s条数据", ids.size()));
        }
        return R.failed(ids, "删除失败");
    }
}
